package wangn.adt;

import wangn.adt.base.Pair;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 输入的非二义性文法G，类似于：
 * S->E+E|E*E
 * E->id
 */
public class CFG {

    private CFG(){}

    private static CFG cfg;

    private static List<Pair<String,String>> grammarList = new ArrayList<>();

    private static Map<String,List<Integer>> sameLeftMap = new HashMap<>();

    public static CFG getInstance(String rawText){
        if (cfg==null){
            getCfg(rawText);
        }
        return cfg;
    }

    //输入的是每个字符代表一个终结符或者非终结符
    private static void getCfg(String rawText){
        int idx = 0;
        StringBuilder sb = new StringBuilder();
        Pair<String,String> pair = new Pair<>();

        //加入扩增文法
        rawText = "@->S\n"+rawText;

        //检查最后一个字符是否为转行符
        if (rawText.charAt(rawText.length()-1)!='\n'){
            rawText+='\n';
        }

        while(idx<rawText.length()){
            switch (rawText.charAt(idx)){
                case '\n':
                    pair.setSecond(sb.toString());
                    grammarList.add(pair);
                    if (!sameLeftMap.containsKey(pair.getFirst())){
                        sameLeftMap.put(pair.getFirst(),new ArrayList<>());
                    }
                    sameLeftMap.get(pair.getFirst()).add(grammarList.size()-1);
                    sb.delete(0,sb.length());
                    pair = new Pair<>();
                    break;
                case '-':
                    if (idx+1<rawText.length() && rawText.charAt(idx+1)=='>'){ //->
                        pair.setFirst(sb.toString());
                        sb.delete(0,sb.length());
                        idx++;
                        break;
                    }
                    sb.append(rawText.charAt(idx));
                    break;
                case '|':
                    pair.setSecond(sb.toString());
                    grammarList.add(pair);
                    if (!sameLeftMap.containsKey(pair.getFirst())){
                        sameLeftMap.put(pair.getFirst(),new ArrayList<>());
                    }
                    sameLeftMap.get(pair.getFirst()).add(grammarList.size()-1);
                    sb.delete(0,sb.length());
                    String first = pair.getFirst();
                    pair = new Pair<>();
                    pair.setFirst(first);
                    break;
                default:
                    sb.append(rawText.charAt(idx));
            }
            idx++;
        }
        cfg = new CFG();
    }

    public Pair<String,String> getGrammar(int idx){
        return idx>=grammarList.size()?null:grammarList.get(idx);
    }

    public int getLength(){return grammarList.size();}

    public List<Integer> findSameLeftProducts(String str){
        return sameLeftMap.getOrDefault(str,new ArrayList<>());
    }
}
